/*
 * File      : fh_sdio.h
 * This file is part of FH8620 BSP for RT-Thread distribution.
 *
 * Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd.
 * All rights reserved
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *  Visit http://www.fullhan.com to get contact with Fullhan.
 *
 * Change Logs:
 * Date           Author       Notes
 */

#ifndef FH_SDIO_H_
#define FH_SDIO_H_

#include <rtthread.h>

//#define __ASIC_BRANCH__

enum
{
    CTRL    = 0x0,   /** Control */
    PWREN   = 0x4,   /** Power-enable */
    CLKDIV  = 0x8,   /** Clock divider */
    CLKSRC  = 0xC,   /** Clock source */
    CLKENA  = 0x10,  /** Clock enable */
    TMOUT   = 0x14,  /** Timeout */
    CTYPE   = 0x18,  /** Card type */
    BLKSIZ  = 0x1C,  /** Block Size */
    BYTCNT  = 0x20,  /** Byte count */
    INTMSK  = 0x24,  /** Interrupt Mask */
    CMDARG  = 0x28,  /** Command Argument */
    CMD     = 0x2C,  /** Command */
    RESP0   = 0x30,  /** Response 0 */
    RESP1   = 0x34,  /** Response 1 */
    RESP2   = 0x38,  /** Response 2 */
    RESP3   = 0x3C,  /** Response 3 */
    MINTSTS = 0x40,  /** Masked interrupt status */
    RINTSTS = 0x44,  /** Raw interrupt status */
    STATUS  = 0x48,  /** Status */
    FIFOTH  = 0x4C,  /** FIFO threshold */
    CDETECT = 0x50,  /** Card detect */
    WRTPRT  = 0x54,  /** Write protect */
    GPIO    = 0x58,  /** General Purpose IO */
    TCBCNT  = 0x5C,  /** Transferred CIU byte count */
    TBBCNT  = 0x60,  /** Transferred host/DMA to/from byte count */
    DEBNCE  = 0x64,  /** Card detect debounce */
    USRID   = 0x68,  /** User ID */
    VERID   = 0x6C,  /** Version ID */
    HCON    = 0x70,  /** Hardware Configuration */
    UHSREG  = 0x74,  /** Reserved */
    BMOD    = 0x80,  /** Bus mode Register */
    PLDMND  = 0x84,  /** Poll Demand */
    DBADDR  = 0x88,  /** Descriptor Base Address */
    IDSTS   = 0x8C,  /** Internal DMAC Status */
    IDINTEN = 0x90,  /** Internal DMAC Interrupt Enable */
    DSCADDR = 0x94,  /** Current Host Descriptor Address */
    BUFADDR = 0x98,  /** Current Host Buffer Address */
    FIFODAT = 0x200, /** FIFO data read write */
};

/* Control register definitions */
#define CTRL_RESET 0x00000001
#define FIFO_RESET 0x00000002
#define DMA_RESET 0x00000004
#define INT_ENABLE 0x00000010
#define READ_WAIT 0x00000040
#define CTRL_USE_IDMAC 0x02000000

/* Interrupt mask defines */
#define INTMSK_CDETECT 0x00000001
#define INTMSK_RESP_ERR 0x00000002
#define INTMSK_CMD_DONE 0x00000004
#define INTMSK_DAT_OVER 0x00000008
#define INTMSK_TXDR 0x00000010
#define INTMSK_RXDR 0x00000020
#define INTMSK_RCRC 0x00000040
#define INTMSK_DCRC 0x00000080
#define INTMSK_RTO 0x00000100
#define INTMSK_DTO 0x00000200
#define INTMSK_HTO 0x00000400
#define INTMSK_VSI INTMSK_HTO  // VSI => Voltage Switch Interrupt
#define INTMSK_FRUN 0x00000800
#define INTMSK_HLE 0x00001000
#define INTMSK_SBE 0x00002000
#define INTMSK_ACD 0x00004000
#define INTMSK_EBE 0x00008000
#define INTMSK_SDIO 0x00010000
#define INTMASK_ERROR                                                        \
    (INTMSK_RESP_ERR | INTMSK_RCRC | INTMSK_DCRC | INTMSK_RTO | INTMSK_DTO | \
     INTMSK_HTO | INTMSK_FRUN | INTMSK_HLE | INTMSK_SBE | INTMSK_EBE)

/*BMOD register define */
#define BMOD_SWR 0x00000001
#define BMOD_DE 0x00000080

/* for STATUS register */
#define GET_FIFO_COUNT(x) (((x)&0x3ffe0000) >> 17)
#define GET_FIFO_DEPTH(x) ((((x)&0x0FFF0000) >> 16) + 1)

/* for IDMA intr register */
#define IDMAINTBITS 0x337

/* PMU related registers */
//#define PMU_REG_BASE           0xF0000000
#define PMU_REG_RST 0xF0000100
#define PMU_REG_CLK_DIV3 0xF0000030
#define PMU_SDC0_RST_BIT 9
#define PMU_SDC1_RST_BIT 10
#define PMU_RST_MODULE(x) \
    *((volatile unsigned int *)(PMU_REG_RST)) = (~((1 << (x))))

/* Define Card status bits (R1 response) */
#define R1CS_ADDRESS_OUT_OF_RANGE 0x80000000
#define R1CS_ADDRESS_MISALIGN 0x40000000
#define R1CS_BLOCK_LEN_ERR 0x20000000
#define R1CS_ERASE_SEQ_ERR 0x10000000
#define R1CS_ERASE_PARAM 0x08000000
#define R1CS_WP_VIOLATION 0x04000000
#define R1CS_CARD_IS_LOCKED 0x02000000
#define R1CS_LCK_UNLCK_FAILED 0x01000000
#define R1CS_COM_CRC_ERROR 0x00800000
#define R1CS_ILLEGAL_COMMAND 0x00400000
#define R1CS_CARD_ECC_FAILED 0x00200000
#define R1CS_CC_ERROR 0x00100000
#define R1CS_ERROR 0x00080000
#define R1CS_UNDERRUN 0x00040000
#define R1CS_OVERRUN 0x00020000
#define R1CS_CSD_OVERWRITE 0x00010000
#define R1CS_WP_ERASE_SKIP 0x00008000
#define R1CS_RESERVED_0 0x00004000
#define R1CS_ERASE_RESET 0x00002000
#define R1CS_CURRENT_STATE_MASK 0x00001e00
#define R1CS_READY_FOR_DATA 0x00000100
#define R1CS_SWITCH_ERROR 0x00000080
#define R1CS_RESERVED_1 0x00000040
#define R1CS_APP_CMD 0x00000020
#define R1CS_RESERVED_2 0x00000010
#define R1CS_APP_SPECIFIC_MASK 0x0000000c
#define R1CS_MANUFAC_TEST_MASK 0x00000003
#define R1CS_ERROR_OCCURED_MAP 0xfdffa080
#define R1CS_CURRENT_STATE(x) (((x)&R1CS_CURRENT_STATE_MASK) >> 9)

/* R5 response */
#define R5_IO_CRC_ERR 0x00008000
#define R5_IO_BAD_CMD 0x00004000
#define R5_IO_GEN_ERR 0x00000800
#define R5_IO_FUNC_ERR 0x00000200
#define R5_IO_OUT_RANGE 0x00000100
#define R5_IO_ERR_BITS 0x0000cb00

enum
{
    NONE_TYPE = 0,
    SD_TYPE,
    SD_2_0_TYPE,
    SDIO_TYPE,
};

enum
{
    CARD_STATE_EMPTY = -1,
    CARD_STATE_IDLE  = 0,
    CARD_STATE_READY = 1,
    CARD_STATE_IDENT = 2,
    CARD_STATE_STBY  = 3,
    CARD_STATE_TRAN  = 4,
    CARD_STATE_DATA  = 5,
    CARD_STATE_RCV   = 6,
    CARD_STATE_PRG   = 7,
    CARD_STATE_DIS   = 8,
    CARD_STATE_INA   = 9
};

enum DmaDescriptorDES1  // Buffer's size field of Descriptor
{
    DescBuf2SizMsk = 0x03FFE000, /* Mask for Buffer2 Size 25:13   */
    DescBuf2SizeShift = 13, /* Shift value for Buffer2 Size */
    DescBuf1SizMsk = 0x00001FFF, /* Mask for Buffer1 Size 12:0    */
    DescBuf1SizeShift = 0, /* Shift value for Buffer2 Size */
};

enum DmaDescriptorDES0  // Control and status word of DMA descriptor DES0
{
    DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31   */
    DescCardErrSummary =
        0x40000000, /* Indicates EBE/RTO/RCRC/SBE/DRTO/DCRC/RE             30 */
    DescEndOfRing =
        0x00000020, /* A "1" indicates End of Ring for Ring Mode           05 */
    DescSecAddrChained =
        0x00000010, /* A "1" indicates DES3 contains Next Desc Address     04 */
    DescFirstDesc = 0x00000008, /* A "1" indicates this Desc contains first 03
                                   buffer of the data */
    DescLastDesc =
        0x00000004, /* A "1" indicates buffer pointed to by this this      02
                       Desc contains last buffer of Data */
    DescDisInt =
        0x00000002, /* A "1" in this field disables the RI/TI of IDSTS     01
                       for data that ends in the buffer pointed to by
                       this descriptor */
};

typedef struct DmaDescStruct
{
    unsigned int desc0; /* control and status information of descriptor */
    unsigned int desc1; /* buffer sizes                                 */
    unsigned int desc2; /* physical address of the buffer 1             */
    unsigned int desc3; /* physical address of the buffer 2             */
} DmaDesc;

typedef struct
{
    unsigned int wkmod;
    volatile DmaDesc *pDmaDesc;
    unsigned int idma_support;
    unsigned int rca;
    unsigned int ip_base;
    unsigned int card_type;
    unsigned int fifo_depth;
    unsigned int fifo_threth;
    unsigned int sectors;
    unsigned int scr[2];
    unsigned int csd[4];
    unsigned int idsts;
    rt_sem_t sem;
    rt_sem_t mutex;
    void (*cb)(void);
} sdc_t;

#define ONE_BIT_MODE (0)
#define FOUR_BIT_MODE (1)

#define BE32_TO_CPU(x)                                                         \
    ((unsigned int)((((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
                    (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) |  \
                    (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) |  \
                    (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24)))

#define synopmob_set_bits(reg, bit_id) \
    *((volatile unsigned int *)(reg)) |= ((unsigned int)(bit_id))
#define synopmob_clear_bits(reg, bit_id) \
    *((volatile unsigned int *)(reg)) &= (~((unsigned int)(bit_id)))
#define synopmob_set_register(reg, val) \
    *((volatile unsigned int *)(reg)) = (val)
#define synopmob_read_register(reg) (*((volatile unsigned int *)(reg)))

enum
{
    ERRNOERROR = 0,

    // for raw interrupt status error
    ERRRESPRECEP,  // 1
    ERRRESPCRC,
    ERRDCRC,
    ERRRESPTIMEOUT,
    ERRDRTIMEOUT,
    ERRUNDERWRITE,
    ERROVERREAD,
    ERRHLE,
    ERRSTARTBIT,
    ERRENDBITERR,  // 10

    // for R1 response
    ERRADDRESSRANGE,  // 11
    ERRADDRESSMISALIGN,
    ERRBLOCKLEN,
    ERRERASESEQERR,
    ERRERASEPARAM,
    ERRPROT,
    ERRCARDLOCKED,
    ERRCRC,
    ERRILLEGALCOMMAND,
    ERRECCFAILED,
    ERRCCERR,
    ERRUNKNOWN,
    ERRUNDERRUN,
    ERROVERRUN,
    ERRCSDOVERWRITE,
    ERRERASERESET,
    ERRFSMSTATE,  // 27

    // for R5 response
    ERRBADFUNC,  // 28

    // others
    ERRCARDNOTCONN,  // 29
    ERRCARDWPROTECT,
    ERRCMDRETRIESOVER,
    ERRNOTSUPPORTED,
    ERRHARDWARE,
    ERRDATANOTREADY,
    ERRCARDINTERNAL,
    ERRACMD41TIMEOUT,
    ERRIDMA,
    ERRNORES,

    ERRNOTEQUAL,
};

#ifdef __ASIC_BRANCH__
#define SDC_WHERE() \
    *((volatile unsigned int *)0x9b800000) = ((unsigned int)(__LINE__))
#define SDC_ERROR()                                   \
    do                                                \
    {                                                 \
        *((volatile unsigned int *)0x9b800008) = ret; \
        *((volatile unsigned int *)0x9a7ff000) = 0;   \
    } while (0)
#define SDC_FINISH() *((volatile unsigned int *)0x9a7ff004) = 0;
#else
#define SDC_WHERE()
#define SDC_ERROR()
#define SDC_FINISH()
#endif  //__ASIC_BRANCH__

#define SDC_WKMOD_25M_STAND_SPEED 0x0002  // 25M standard speed
#define SDC_WKMOD_50M_HI_SPEED 0x0004     // 50M high speed
#define SDC_WKMOD_1WIRE 0x0008            // 1 wire transfer mode
#define SDC_WKMOD_4WIRE 0x0010            // 4 wire transfer mode

#define SDC_RW_USE_DMA 0x80000000  // Use DMA transfer?

typedef void *HSDC;

// map to DmaDesc
typedef struct _buf_chain
{
    unsigned int csi;         // desc0
    unsigned int size;        // desc1
    void *buf;                // desc2
    struct _buf_chain *next;  // desc3
} buf_chain_t;

/*
  * for SD card
   */
extern int sdc_is_connected(unsigned int which);
extern int sdc_init(unsigned int which, unsigned int wkmod,
                    unsigned int *dma_desc /*4Byte aligned,16 bytes space*/,
                    HSDC *phandle);
extern int sdc_read_block(HSDC handle, unsigned int blk, unsigned int num,
                          unsigned char *buffer);
extern int sdc_write_block(HSDC handle, unsigned int blk, unsigned int num,
                           unsigned char *buffer);
extern int sdc_erase_block(HSDC handle, unsigned int blk, unsigned int num);
extern int sdc_get_sector_num(HSDC handle);
extern int sdc_set_clk_divider(unsigned int divider);

/*
  * for SDIO WIFI card
   */
extern void fh_sdio0_init(void);
extern void fh_sdio1_init(void);
extern void fh_sdio_init(void);
extern int sdio_init(unsigned int which, unsigned int wkmod,
                     unsigned int *dma_desc /*4Byte aligned,16 bytes space*/,
                     HSDC *phandle);
extern int sdio_high_speed_mode(HSDC handle, int bitwidth, int freq);
extern int sdio_enable_card_int(HSDC handle, int enable);
extern int sdio_set_card_int_cb(HSDC handle, void (*cb)(void));
extern int sdio_drv_read(HSDC handle, unsigned int addr, unsigned int fn,
                         unsigned int bcnt, unsigned int bsize,
                         unsigned char *buf);
extern int sdio_drv_write(HSDC handle, unsigned int addr, unsigned int fn,
                          unsigned int bcnt, unsigned int bsize,
                          unsigned char *buf);
extern int sdio_drv_creg_read(HSDC handle, int addr, int fn,
                              unsigned int *resp);
extern int sdio_drv_creg_write(HSDC handle, int addr, int fn,
                               unsigned char data, unsigned int *resp);

extern void inv_dcache_range(unsigned long start, unsigned long len);
extern void flush_dcache_range(unsigned long start, unsigned long len);

#ifdef DONT_COPY_NET_PAYLOAD_TO_SEND
int sdio_drv_chain_write(sdc_t* sdc, unsigned int addr, unsigned int fn,
                         unsigned int bcnt, unsigned int bsize,
                         buf_chain_t* chain);
#endif
int sdc_deinit(HSDC handle);
#endif  //__sdcard_h__
